package com.ckx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ckx.constants.SystemConstants;
import com.ckx.domain.dto.*;
import com.ckx.domain.entity.LoginUserDetails;
import com.ckx.domain.entity.User;
import com.ckx.domain.entity.UserRole;
import com.ckx.domain.vo.*;
import com.ckx.enums.AppHttpCodeEnum;
import com.ckx.exception.SystemException;
import com.ckx.mapper.UserMapper;
import com.ckx.service.RoleService;
import com.ckx.service.UserRoleService;
import com.ckx.service.UserService;
import com.ckx.utils.BeanCopyUtil;
import com.ckx.utils.RedisCache;
import com.ckx.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RoleService roleService;


    @Override
    public UserInfoVo userInfo(Long id) {

        User user = this.getById(id);
        if (Objects.isNull(user)) {
            throw new SystemException(AppHttpCodeEnum.ARGS_FAIL);
        }
        return BeanCopyUtil.copyBean(user, UserInfoVo.class);

    }

    @Override
    public void updateUserInfo(UserDto userDto) {
        User user = BeanCopyUtil.copyBean(userDto, User.class);
        user.setUpdateTime(new Date());
//        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        Long userId = SecurityUtils.getUserId();
        //更新前删除信息,防止更新时读取数据不一致
        redisCache.deleteObject("BlogLogin:" + userId);
        //更新数据
        if (this.updateById(user)) {
            LoginUserDetails loginUser = SecurityUtils.getLoginUser();
            User user1 = loginUser.getUser();
            user1.setAvatar(userDto.getAvatar());
            user1.setEmail(userDto.getEmail());
            user1.setNickName(user.getNickName());
            user1.setSex(user.getSex());
            //重新存入用户数据
            redisCache.setCacheObject("BlogLogin:" + userId, loginUser, 60, TimeUnit.MINUTES);
        }

    }

    @Override
    public void register(UserRegisterDto userRegisterDto) {
        //数据校验
        if (!StringUtils.hasText(userRegisterDto.getUserName()) && !StringUtils.hasText(userRegisterDto.getNickName())) {
            throw new SystemException(AppHttpCodeEnum.ARGS_FAIL);
        }

        //数据冲突校验
        if (hasName(userRegisterDto.getUserName(), userRegisterDto.getNickName())) {
            throw new SystemException(AppHttpCodeEnum.NAME_EXIST);
        }

        User user = BeanCopyUtil.copyBean(userRegisterDto, User.class);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        //存入数据库
        this.save(user);
    }

    @Override
    public PageVo listByPage(Integer pageNum, Integer pageSize, User user) {

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().like(StringUtils.hasText(user.getUserName()), User::getUserName, user.getUserName());
        wrapper.lambda().like(StringUtils.hasText(user.getPhonenumber()), User::getPhonenumber, user.getPhonenumber());

        Page<User> page = new Page<>(pageNum, pageSize);
        page(page, wrapper);

        List<UserVo> userVos = page.getRecords().stream()
                .map(u -> BeanCopyUtil.copyBean(u, UserVo.class))
                .collect(Collectors.toList());

        return new PageVo(userVos, page.getTotal());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser4Admin(UserAddDto userAddDto) {

        User user = BeanCopyUtil.copyBean(userAddDto, User.class);
        //名称冲突检测
        if (hasName(user.getUserName(), user.getNickName())) {
            throw new SystemException(AppHttpCodeEnum.NAME_EXIST);
        }
        //创建管理员
        user.setType(SystemConstants.ADMAIN);
        //加密密码
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        //添加管理员
        if (this.save(user)) {
            //存储管理员对应角色
            List<Long> roleIds = userAddDto.getRoleIds();
            List<UserRole> userRoles = roleIds.stream()
                    .map(roleId -> new UserRole(user.getId(), roleId))
                    .collect(Collectors.toList());
            userRoleService.saveBatch(userRoles);
        }
    }

    @Override
    public void changeStatus(UserStatusDto userStatusDto) {
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.lambda().set(User::getStatus, userStatusDto.getStatus());
        wrapper.lambda().eq(User::getId, userStatusDto.getUserId());
        this.update(wrapper);
    }

    @Override
    public UserInfoByAdminVo getUserInfo(Long id) {
        if (Objects.isNull(id) || id <= 0) {
            throw new SystemException(AppHttpCodeEnum.ARGS_FAIL);
        }
        //查询用户
        User user = this.getById(id);
        if (Objects.isNull(user)) {
            throw new SystemException(AppHttpCodeEnum.ARGS_FAIL);
        }
        //查询对应角色信息
        QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserRole::getUserId, id);
        List<UserRole> userRoles = userRoleService.getBaseMapper().selectList(wrapper);
        List<Long> roleIds = new ArrayList<>();
        userRoles.forEach(userRole -> roleIds.add(userRole.getRoleId()));

        //查询所有角色信息
        List<RoleVo> roleVos = roleService.listAllRole();
        //封装 vo
        return new UserInfoByAdminVo(roleIds, roleVos, user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UserUpdateDto userUpdateDto) {

        User user = BeanCopyUtil.copyBean(userUpdateDto, User.class);
        //更新用户信息
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(User::getId, user.getId());
        if (this.update(user, wrapper)) {
            //更新用户角色信息
            List<Long> roleIds = userUpdateDto.getRoleIds();
            List<UserRole> userRoles = new ArrayList<>();
            roleIds.forEach(roleId->{
                userRoles.add(new UserRole(user.getId(), roleId));
            });
            //先删除
            userRoleService.remove(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, user.getId()));
            //后更新
            userRoleService.saveBatch(userRoles);
        }

    }

    @Override
    public void del4DelFlag(Long id) {
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.lambda().set(User::getDelFlag, SystemConstants.DELFLAG);
        wrapper.lambda().eq(User::getId, id);
        this.update(wrapper);
    }

    private boolean hasName(String username, String nickName) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(User::getUserName, username)
                .or()
                .eq(User::getNickName, nickName);

        return this.count(wrapper) > 0;
    }

}
